#pragma once
//环形队列本身不是临界资源,但其中每一个位置是临界资源,需要穿行访问
//信号量保证了生产和消费的互斥 (当消费和生产位置重叠,信号量做到了访问顺序控制)
//还需要分别加锁来保证消费-消费 ,生产-生产间的互斥关系
#include <array>
#include <pthread.h>
#include <semaphore.h>
using namespace std;
template <typename T, size_t Nm = 5>
class ring_queue_t
{
public:
    ring_queue_t()
        : _array(), _comcume_index(0), _produce_index(0)
    {
        pthread_mutex_init(&_concume_mutex, nullptr);
        pthread_mutex_init(&_produce_mutex, nullptr);
        sem_init(&_resource_sem, 0, 0);
        sem_init(&_room_sem, 0, Nm);
    }
    ~ring_queue_t()
    {
        pthread_mutex_destroy(&_concume_mutex);
        pthread_mutex_destroy(&_produce_mutex);
        sem_destroy(&_room_sem);
        sem_destroy(&_resource_sem);
    }

public:
    void push(T &resource)
    {
        //先等待空间,获取信号量
        sem_wait(&_room_sem);
        //获取生产锁,保证临界资源(index对应的空间)安全
        pthread_mutex_lock(&_produce_mutex);
        //临界区
        {
            //放入资源,对下标取模
            _array[_produce_index++] = resource;
            _produce_index %= Nm;
        }
        //解锁
        pthread_mutex_unlock(&_produce_mutex);
        //队列里资源增加了
        sem_post(&_resource_sem);
    }
    T pop()
    {
        //先等待资源,获取信号量
        sem_wait(&_resource_sem);
        T resource = T();
        pthread_mutex_lock(&_concume_mutex);
        {
            resource = _array[_comcume_index++];
            _comcume_index %= Nm;
        }
        //队列空间增加了
        pthread_mutex_unlock(&_concume_mutex);
        sem_post(&_room_sem);
        return resource;
    }

private:
    pthread_mutex_t _concume_mutex;
    pthread_mutex_t _produce_mutex;
    sem_t _resource_sem;
    sem_t _room_sem;
    size_t _comcume_index;
    size_t _produce_index;
    array<T, Nm> _array;
};